package club.westudy.distributed.lock;

/**
 * 分布式锁服务定义接口
 */
public interface DistributedLockService {
    /**
     * 初始化分布式锁
     */
    void init();

    /**
     * 立即强制关闭分布式锁服务
     */
    void shutdownNow();

    /**
     * 关闭分布式锁服务
     * 1.当实现支持非强制关闭时，该方法执行后将发生阻塞
     * 2.当实现支持强制关闭时，该方法执行后将释放资源，并强制杀掉持有锁的线程
     *
     * @param force 是否强制关闭锁服务
     */
    void shutdown(boolean force);

    /**
     * 获取锁
     *
     * @param feature           锁特征
     * @param maxLeaseTimeMs    持有锁最长时间（单位毫秒）
     * @param tryLockWaitTimeMs 等待锁超时时间（单位毫秒）
     * @return 执行成功为真
     */
    boolean obtain(String feature, long maxLeaseTimeMs, long tryLockWaitTimeMs);


    /**
     * 执行临界区代码
     *
     * @param feature                锁特征
     * @param criticalRegionRunnable 临界区业务代码
     * @param maxLeaseTimeMs         最大锁租期，单位毫秒
     * @param tryLockWaitTimeMs      锁排队最长等待时间，单位毫秒
     * @return 执行成功为真
     */
    boolean execute(String feature,
                    DistributedLockService.CriticalRegionRunnable criticalRegionRunnable,
                    long maxLeaseTimeMs,
                    long tryLockWaitTimeMs);

    /**
     * 释放某个特征的锁，此方法用于编程式方式使用分布式锁服务
     *
     * @param feature 特征
     * @return 执行成功为真
     */
    boolean release(String feature);

    /**
     * 临界区执行体，用于封装需要执行的业务代码
     * 1.正常执行不发生异常的情况下，自动解锁
     * 2.执行发生异常时，也会自动解锁
     */
    interface CriticalRegionRunnable {
        /**
         * 执行临界区代码之前的前置处理
         *
         * @param ctx 临界区上下文
         * @throws Throwable 抛出异常
         */
        default void before(CriticalRegionContext ctx) throws Throwable {
        }

        /**
         * 执行业务代码
         *
         * @param ctx 临界区上下文
         * @throws Throwable 抛出异常
         */
        void run(CriticalRegionContext ctx) throws Throwable;

        /**
         * 执行临界区代码之前的前置处理
         *
         * @param ctx 临界区上下文
         * @throws Throwable 抛出异常
         */
        default void after(CriticalRegionContext ctx) throws Throwable {
        }
    }

    /**
     * 临界区上下文，承载分布式锁的相关信息
     */
    interface CriticalRegionContext {
        /**
         * 设置是否已经加锁
         * @param locked
         */
        void setLocked(boolean locked);
        /**
         * 是否已经加锁成功
         *
         * @return 执行成功返回真
         */
        boolean isLocked();

        /**
         * 获取分布式锁的特征，与竞争特征相同，代表了唯一的一把锁
         *
         * @return 锁特征数组
         */
        String getLockFeature();

        /**
         * 获取分布式锁获取租约开始的时间，单位毫秒
         *
         * @return 开始持有时间
         */
        long getLeaseBeginTimeMs();

        /**
         * 最长租约时间，单位毫秒
         * @return
         */
        long maxLeaseTimeMs();

        /**
         * 尝试加锁等待超时时间，单位毫秒
         * @return 等待超时时间
         */
        long tryLockWaitTimeMs();
    }
}